package Snake
{	
	import Map.CMapTile;
	
	import flash.display.Sprite;
	
	import srdk.SRAABB;
	
	public class CSnakePiece
	{
		public static const PIECE_TYPE_HEAD		:uint = 1;
		public static const PIECE_TYPE_BODY		:uint = 2;
		
		public static const MOVE_DIRECTION_NONE	:uint = 0;
		public static const MOVE_DIRECTION_UP	:uint = 1;
		public static const MOVE_DIRECTION_DOWN	:uint = 2;
		public static const MOVE_DIRECTION_LEFT	:uint = 3;
		public static const MOVE_DIRECTION_RIGHT:uint = 4;
		
		public static const STATE_IDLE			:uint = 0;
		public static const STATE_MOVE			:uint = 1;
		private var m_state :uint = STATE_IDLE;
		
		private var m_sprite :Sprite;
		
		private var m_aabb :SRAABB;
		
		private var m_refSnake :CSnake;
		private var m_nPositionX :Number;
		private var m_nPositionY :Number;
		
		private var m_nDestPositionX :Number;
		private var m_nDestPositionY :Number;
		private var m_nSpeedX :Number = 0;
		private var m_nSpeedY :Number = 0;
		private var m_nDirection :uint = MOVE_DIRECTION_NONE;
		
		private var m_refBackPiece :CSnakePiece = null;
		
		public function get sprite() :Sprite { return m_sprite; }
		public function get aabb() :SRAABB { return m_aabb; }
		public function get state() :uint { return m_state; }
		public function get nDestPositionX() :Number { return m_nDestPositionX; }
		public function get nDestPositionY() :Number { return m_nDestPositionY; }
		
		public function CSnakePiece(refSnake :CSnake, nPieceType :uint, nMapPosX :int, nMapPosY :int)
		{
			m_refSnake = refSnake;
			
			switch(nPieceType)
			{
			case PIECE_TYPE_HEAD:
				m_sprite = new CSprite_SnakeHeadPiece();
				break;
			case PIECE_TYPE_BODY:
				m_sprite = new CSprite_SnakeBodyPiece();
				break;
			}
			
			m_nPositionX = nMapPosX*CMapTile.TILE_WIDTH + CMapTile.TILE_WIDTH/2;
			m_nPositionY = nMapPosY*CMapTile.TILE_HEIGHT + CMapTile.TILE_HEIGHT/2;
			m_nDestPositionX = m_nPositionX;
			m_nDestPositionY = m_nPositionX;
			
			m_aabb = new SRAABB();
			m_aabb.Init(m_nPositionX, m_nPositionY, CMapTile.TILE_WIDTH-1, CMapTile.TILE_HEIGHT-1);
			UpdatePosition();
		}
		public function Destroy() :void
		{
			m_refSnake = null;
			m_sprite = null;
			m_aabb = null;
			m_refBackPiece = null;
		}
		public function SetBackPiece(refBackPiece :CSnakePiece) :void
		{
			m_refBackPiece = refBackPiece;
		}
		public function GetMapPosX() :uint
		{
			return Math.floor((m_nPositionX - CMapTile.TILE_WIDTH/2)/CMapTile.TILE_WIDTH);
		}
		public function GetMapPosY() :uint
		{
			return Math.floor((m_nPositionY - CMapTile.TILE_HEIGHT/2)/CMapTile.TILE_HEIGHT);
		}
		public function IsIdle() :Boolean
		{
			if (state == CSnakePiece.STATE_IDLE)
			{
				if (m_refBackPiece != null)
					return m_refBackPiece.IsIdle();
				else return true;
			}
			else
				return false;
		}
		public function SetMoveInfo(nDirection :uint) :void
		{
			if (m_refSnake == null) return;
			
			m_state = STATE_MOVE;
			m_nDirection = nDirection;
			
			var nDestMapPosX :uint = GetMapPosX();
			var nDestMapPosY :uint = GetMapPosY();
			
			switch (nDirection)
			{
			case MOVE_DIRECTION_UP:
				m_nSpeedX = 0;
				m_nSpeedY = -m_refSnake.nMoveSpeed;
				nDestMapPosY--;
				break;
			case MOVE_DIRECTION_DOWN:
				m_nSpeedX = 0;
				m_nSpeedY = m_refSnake.nMoveSpeed;
				nDestMapPosY++;
				break;
			case MOVE_DIRECTION_LEFT:
				m_nSpeedX = -m_refSnake.nMoveSpeed;
				m_nSpeedY = 0;
				nDestMapPosX--;
				break;
			case MOVE_DIRECTION_RIGHT:
				m_nSpeedX = m_refSnake.nMoveSpeed;
				m_nSpeedY = 0;
				nDestMapPosX++;
				break;
			}
			
			m_nDestPositionX = nDestMapPosX*CMapTile.TILE_WIDTH + CMapTile.TILE_WIDTH/2;
			m_nDestPositionY = nDestMapPosY*CMapTile.TILE_HEIGHT + CMapTile.TILE_HEIGHT/2;
			
			if (m_refBackPiece == null) return;
			
			var nBackPieceDirection :uint = MOVE_DIRECTION_NONE;
			if (m_refBackPiece.GetMapPosY()-GetMapPosY() > 0)
			{
				nBackPieceDirection = MOVE_DIRECTION_UP;
			}
			else if (m_refBackPiece.GetMapPosY()-GetMapPosY() < 0)
			{
				nBackPieceDirection = MOVE_DIRECTION_DOWN;
			}
			else if (m_refBackPiece.GetMapPosX()-GetMapPosX() > 0)
			{
				nBackPieceDirection = MOVE_DIRECTION_LEFT;
			}
			else if (m_refBackPiece.GetMapPosX()-GetMapPosX() < 0)
			{
				nBackPieceDirection = MOVE_DIRECTION_RIGHT;
			}
			
			if (nBackPieceDirection == MOVE_DIRECTION_NONE)
			{
				return;
			}
			
			m_refBackPiece.SetMoveInfo(nBackPieceDirection);
		}
		public function Update(tick :Number) :void
		{
			switch(state)
			{
			case STATE_IDLE:	OnState_Idle(tick);	break;
			case STATE_MOVE:	OnState_Move(tick);	break;
			}
			
			UpdatePosition();
			
			if (m_refBackPiece != null) m_refBackPiece.Update(tick);
		}
		private function OnState_Idle(tick :Number) :void
		{
			
		}
		private function OnState_Move(tick :Number) :void
		{
			m_nPositionX += m_nSpeedX*tick;
			m_nPositionY += m_nSpeedY*tick;
			
			var nDX :Number = m_nDestPositionX-m_nPositionX;
			var nDY :Number = m_nDestPositionY-m_nPositionY;
			
			var nTX :Number = 0;
			var nTY :Number = 0;
			if (m_nSpeedX != 0)
				nTX = nDX/m_nSpeedX;
			if (m_nSpeedY != 0)
				nTY = nDY/m_nSpeedY;
				
			if (nTX <= 0 && nTY <= 0)
			{
				m_nPositionX = m_nDestPositionX;
				m_nPositionY = m_nDestPositionY;
				m_state = STATE_IDLE;
			}
			
//			switch(m_nDirection)
//			{
//			case MOVE_DIRECTION_LEFT:
//				if (m_nDestPositionX - m_nPositionX >= 0)
//				{
//					m_nPositionX = m_nDestPositionX;
//					m_state = STATE_IDLE;
//					trace("Here LEFT!");
//				}
//				break;
//			case MOVE_DIRECTION_RIGHT:
//				if (m_nDestPositionX - m_nPositionX <= 0)
//				{
//					m_nPositionX = m_nDestPositionX;
//					m_state = STATE_IDLE;
//					trace("Here RIGHT!");
//				}
//				break;
//			case MOVE_DIRECTION_UP:
//				if (m_nDestPositionY - m_nPositionY >= 0)
//				{
//					m_nPositionY = m_nDestPositionY;
//					m_state = STATE_IDLE;
//					trace("Here UP!");
//				}
//				break;
//			case MOVE_DIRECTION_DOWN:
//				if (m_nDestPositionY - m_nPositionY <= 0)
//				{
//					m_nPositionY = m_nDestPositionY;
//					m_state = STATE_IDLE;
//					trace("Here DOWN!");
//				}
//				break;
//			}
		}
		
		private function UpdatePosition() :void
		{
			if (m_sprite == null) return;
			m_sprite.x = m_nPositionX;
			m_sprite.y = m_nPositionY;
			
			UpdateAABB();
		}
		private function UpdateAABB() :void
		{
			if (m_aabb == null) return;
			m_aabb.SetPosition(m_nPositionX, m_nPositionY);
		}
		private function MoveBackPiece(nDestMapPosX :int, nDestMapPosY :int) :void
		{
//			var nBackPieceDirection :uint = MOVE_DIRECTION_NONE;
//			if (m_refBackPiece.nMapPosY-nDestMapPosY > 0)
//				nBackPieceDirection = MOVE_DIRECTION_UP;
//			else if (m_refBackPiece.nMapPosY-nDestMapPosY < 0)
//				nBackPieceDirection = MOVE_DIRECTION_DOWN;
//			else if (m_refBackPiece.nMapPosX-nDestMapPosX > 0)
//				nBackPieceDirection = MOVE_DIRECTION_LEFT;
//			else if (m_refBackPiece.nMapPosX-nDestMapPosX < 0)
//				nBackPieceDirection = MOVE_DIRECTION_RIGHT;
//			
//			m_refBackPiece.Move(nBackPieceDirection);
		}
	}
}